import std.stdio;
import irrlicht;

enum
{
    ID_IsNotPickable = 0,
    IDFlag_IsPickable = 1 << 0,
    IDFlag_IsHighlightable = - 1 << 1
}

void main()
{
    E_DRIVER_TYPE driverType = driverChoiceConsole();
    assert(driverType != E_DRIVER_TYPE.EDT_COUNT);
    
    IrrlichtDevice device = createDevice(driverType, new UintDimension2D(640,480), 16, false, false, false, null);
    
    assert(device, "Could not create selected driver.");
    
    IVideoDriver driver = device.getVideoDriver();
    ISceneManager smgr = device.getSceneManager();
    
    device.getFileSystem().addZipFileArchive("media/map-20kdm2.pk3");
    
    IAnimatedMesh q3levelmesh = smgr.getMesh("20kdm2.bsp");
    IMeshSceneNode q3node;    
    if(q3levelmesh)
        q3node = smgr.addOctreeSceneNode(q3levelmesh.getMesh(0), null, IDFlag_IsPickable);
    
    ITriangleSelector selector;    
    if(q3node)
    {
        q3node.setPosition(new FloatVector3D(-1350, -130, -1400));
        
        selector = smgr.createOctreeTriangleSelector(q3node.getMesh(), q3node, 128);
        q3node.setTriangleSelector(selector);
    }
    
    ICameraSceneNode camera = smgr.addCameraSceneNodeFPS(null,100.0,0.3, ID_IsNotPickable, null,0,true,3.f);
    camera.setPosition(new FloatVector3D(50,50,-60));
    camera.setTarget(new FloatVector3D(-70,30,-60));
    
    if(selector)
    {
        ISceneNodeAnimator anim = smgr.createCollisionResponseAnimator(selector, camera,
                                                                       new FloatVector3D(30,50,30),
                                                                       new FloatVector3D(0,-10,0),
                                                                       new FloatVector3D(0,30,0));
        
        camera.addAnimator(anim);
    }
    
    device.getCursorControl().setVisible(false);
    
    auto bill = smgr.addBillboardSceneNode();
    bill.setMaterialType(E_MATERIAL_TYPE.EMT_TRANSPARENT_ADD_COLOR);
    bill.setMaterialTexture(0, driver.getTexture("media/particle.bmp"));
    bill.setMaterialFlag(E_MATERIAL_FLAG.EMF_LIGHTING, false);
    bill.setMaterialFlag(E_MATERIAL_FLAG.EMF_ZBUFFER, false);
    bill.setSize(new FloatDimension2D(20.0, 20.f));
    bill.setID(ID_IsNotPickable); //do not ray-pick it
    
    IAnimatedMeshSceneNode node;
    
    node = smgr.addAnimatedMeshSceneNode(smgr.getMesh("media/faerie.md2"), null, IDFlag_IsPickable | IDFlag_IsHighlightable);
    
    node.setPosition(new FloatVector3D(-70,-15,-120));
    node.setScale(new FloatVector3D(2,2,2));
    node.setMD2Animation(EMD2_ANIMATION_TYPE.EMAT_POINT);
    node.setAnimationSpeed(20.0);
    SMaterial material = new SMaterial();
    material.setTexture(0, driver.getTexture("media/faerie2.bmp"));
    material.Lighting = true;
    material.NormalizeNormals = true;

    //The next two lines will do nothing if SWIG not patched
    //to disable anti-infinite-recursion
    node.getMaterial(0).setTexture(0,driver.getTexture("media/faerie2.bmp"));
    node.getMaterial(0).assign(material);  //copy assignment, node.getMaterial(0) = material;
    
    selector = smgr.createTriangleSelector(node);
    node.setTriangleSelector(selector);
    
    node = smgr.addAnimatedMeshSceneNode(smgr.getMesh("media/dwarf.x"),
                                         null, IDFlag_IsPickable | IDFlag_IsHighlightable);
    node.setPosition(new FloatVector3D(-70,-66,0));
    node.setRotation(new FloatVector3D(0,-90,0));
    selector = smgr.createTriangleSelector(node);
    node.setTriangleSelector(selector);
    
    node = smgr.addAnimatedMeshSceneNode(smgr.getMesh("media/ninja.b3d"),
                                         null, IDFlag_IsPickable | IDFlag_IsHighlightable);
    
    node.setScale(new FloatVector3D(10,10,10));
    node.setPosition(new FloatVector3D(-70,-66,-60));
    node.setRotation(new FloatVector3D(0,90,0));
    node.setAnimationSpeed(10.0);
    
    //The next line will do nothing if SWIG not patched
    //to disable anti-infinite-recursion
    node.getMaterial(0).NormalizeNormals = true;
    selector = smgr.createTriangleSelector(node);
    node.setTriangleSelector(selector);
    
    material.setTexture(0,null);
    material.Lighting = false;
    
    ILightSceneNode light = smgr.addLightSceneNode(null, new FloatVector3D(-60,100,400), new SColorf(1,1,1,1), 600);
    light.setID(ID_IsNotPickable);
    
    ISceneNode highlightedSceneNode;
    ISceneCollisionManager collMan = smgr.getSceneCollisionManager();
    int lastFPS = -1;
    
    material.Wireframe = true;

    while(device.run())
    if(device.isWindowActive())
    {
        driver.beginScene(true,true);
        smgr.drawAll();

        if(highlightedSceneNode)
        {
            highlightedSceneNode.setMaterialFlag(E_MATERIAL_FLAG.EMF_LIGHTING, true);
            highlightedSceneNode = null;
        }
        
        FloatLine3D ray = new FloatLine3D();
        ray.start = camera.getPosition();
        ray.end = ray.start + (camera.getTarget() - ray.start).normalize() * 1000;
        
        auto intersection = new FloatVector3D();
        auto hitTriangle = new FloatTriangle3D();

        ISceneNode selectedSceneNode = collMan.getSceneNodeAndCollisionPointFromRay(
                                            ray,
                                            intersection,
                                            hitTriangle,
                                            IDFlag_IsPickable,
                                            null);
        if(selectedSceneNode)
        {
            bill.setPosition(intersection);

            driver.setTransform(E_TRANSFORMATION_STATE.ETS_WORLD, new FloatCMatrix4());
            driver.setMaterial(material);
            driver.draw3DTriangle(hitTriangle, new SColor(0,255,0,0));
            
            if((selectedSceneNode.getID() & IDFlag_IsHighlightable) == IDFlag_IsHighlightable)
            {
                highlightedSceneNode = selectedSceneNode;
                
                highlightedSceneNode.setMaterialFlag(E_MATERIAL_FLAG.EMF_LIGHTING, false);
            }
        }
        
        driver.endScene();
        
        int fps = driver.getFPS();
        
        if(lastFPS != fps)
        {
            wstring str = "Collision detection example - Irrlicht Engine [";
            str ~= driver.getName();
            str ~= "] FPS:";
            str ~= std.conv.to!wstring(fps);
            
            device.setWindowCaption(str);
            lastFPS = fps;
        }
    }
}